
package com.sailboard.iot.opm.utils;

import com.alibaba.fastjson.JSONObject;
import com.sailboard.iot.opm.utils.encrypt.Digests;
import com.sailboard.iot.opm.utils.encrypt.MD5Util;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工具类
 */
public class Utils {

    //统一社会信用代码
    static String isCreditCode = "true";
    static String error_CreditCode = "社会信用代码有误";
    static String error_CreditCode_min = "社会信用代码不足18位，请核对后再输！";
    static String error_CreditCode_max = "社会信用代码大于18位，请核对后再输！";
    static String error_CreditCode_empty ="社会信用代码不能为空！";
    private static Map<String,Integer> datas = null;
    private static char[] pre17s;
    static int[] powerS = {1,3,9,27,19,26,16,17,20,29,25,13,8,24,10,30,28};
    // 社会统一信用代码不含（I、O、S、V、Z） 等字母
    static char[] code = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','T','U','W','X','Y'};

    //统一社会信用代码
    /**
     * 判断是否是一个有效的社会信用代码
     * @param creditCode
     * @return
     */
    public static String isCreditCode(String creditCode){
        initDatas(code.length);
        pre17(creditCode);
        if("".equals(creditCode)||" ".equals(creditCode)){
            return error_CreditCode_empty;
        }else if(creditCode.length()<18){
            return  error_CreditCode_min;
        }else if(creditCode.length()>18){
            return  error_CreditCode_max;
        }else{
            int sum =  sumS(pre17s);
            int temp = sum%31;
            temp = temp==0?31:temp;
            return creditCode.substring(17,18).equals(code[31-temp]+"")?isCreditCode:error_CreditCode;
        }
    }

    /**
     * @param chars
     * @return
     */
    private static int sumS(char[] chars){
        int sum = 0;
        for(int i=0;i<chars.length;i++){
            int code = datas.get(chars[i]+"");
            sum+=powerS[i]*code;
        }
        return sum;

    }

    /**
     * 获取前17位字符
     * @param creditCode
     */
    static  void  pre17(String creditCode){
        String pre17 = creditCode.substring(0,17);
        pre17s = pre17.toCharArray();
    }

    /**
     * 初始化数据
     * @param count
     */
    static void  initDatas(int count){
        datas = new HashMap<>();
        for(int i=0;i<code.length;i++){
            datas.put(code[i]+"",i);
        }
    }

    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 得到显示时间
     * @return   yyyy-MM-dd HH:mm:ss
     */
    public static String dateToString(Date date) {
        if (date == null) {
            return null;
        }
        return sdf.format(date);
    }

    /**
     * 根据显示时间得到日期
     * @param time  yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static Date stringToDate(String time) {
        if (StringUtils.isBlank(time)) {
            return null;
        }
        try {
            return sdf.parse(time);
        } catch (ParseException e) {
            e.printStackTrace();
            return new Date();
        }
    }


    /**
     * 将对象转成json串
     * @param obj
     * @return
     */
    public static String toJson(Object obj) {
        if (obj == null)
            return null;
        JSONObject result = new JSONObject();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (int j = 0; j < fields.length; j++) {
            fields[j].setAccessible(true);
            // 字段名
            String key = fields[j].getName();
            // 字段类型
            String type = fields[j].getType().getName();
            try {
                // 字段值
                Object value = fields[j].get(obj);
                if (value != null) {
                    //如果是Date类型，转换成 yyyy-MM-dd HH:mm:ss
                    if (type.equalsIgnoreCase("java.util.Date")) {
                        value = Utils.dateToString((Date) value);
                    }
                    result.put(key, value.toString());
                } else {
                    //如果是Integer类型，转换成0
                    if (type.equalsIgnoreCase("java.lang.Integer") || type.equalsIgnoreCase("java.lang.Long")) {
                        value = 0;
                        result.put(key, value.toString());
                    }
                }
            } catch (Exception e) {
                System.out.println("object field transfer failed, but it`s ok. field = " + key + ", type = " + type);
            }
        }
        return JSONObject.toJSONString(result);
    }

    /**
     * 将json串转成对象
     * @param json
     * @param clazz
     * @return
     */
    public static Object fromJson(String json, Class clazz) {
        if (StringUtils.isNotEmpty(json)) {
            return JSONObject.parseObject(json, clazz);
        }
        return null;
    }

    /**
     * 将newObj中待更新的字段值，填充到oldObj中做替换
     * @param oldObj
     * @param newObj
     * @return  更新后的obj
     */
    public static Object fillObj(Object oldObj, Object newObj) {
        Field[] oldf = oldObj.getClass().getDeclaredFields();
        Field[] newf = newObj.getClass().getDeclaredFields();
        for (int j = 0; j < oldf.length; j++) {
            try {
                newf[j].setAccessible(true);
                if (newf[j].get(newObj) != null) {
                    oldf[j].setAccessible(true);
                    oldf[j].set(oldObj, newf[j].get(newObj));
                }
            } catch (IllegalAccessException e) {
                System.out.println("object field transfer failed, but it`s ok. field = " + newf[j].getName() + ", type = " + newf[j].getType().getName());
            }
        }
        return oldObj;
    }


    /**
     * 生成随机盐
     * @return
     */
    public static String generateSalt() {
        return Encodes.encodeHex(Digests.generateSalt(4));
    }

    /**
     * 密码加密
     * @param salt
     * @param password
     * @return
     */
    public static String encryptPassword(String salt, String password) {
        return MD5Util.sha256Hex(salt, password);
    }

    public static void main(String[] args) {
        String salt = generateSalt();
        String password = encryptPassword(salt, "111111");

        System.out.println("salt="+salt);
        System.out.println("password="+password);
    }

    public static String genToken() {
        try {
            return DigestUtils.md5DigestAsHex(UUID.randomUUID().toString().getBytes("UTF-8")).toUpperCase();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static final String ZS_TOKEN_PRE = "ZS-";
    public static final String LS_TOKEN_PRE = "LS-";
    public static final String LS_TOKEN = "L";
    public static final String DL_TOKEN = "X";

    public static String genZSToken() {
        String token = genToken();
        if(token != null) {
            return ZS_TOKEN_PRE + token;
        }
        return token;
    }

    public static String genLSToken() {
        String token = genToken();
        if(token != null) {
            return LS_TOKEN_PRE + token;
        }
        return token;
    }

    /**
     * 获得 token true 登陆 token, false 未登陆 token
     * */
    public static String getToken(Boolean b) {

        String token = genToken();
        if(b) {

            return DL_TOKEN+token;

        } else {

            return LS_TOKEN+token;

        }
    }

    /**
     * 验证手机号码，11位数字
     * @param mobile
     * @return
     */
    public static boolean checkMobile(String mobile) {
        if (mobile == null) {
            return false;
        }
        String regex = "\\d{11}";
        return Pattern.matches(regex, mobile);
    }

    /**
     * 检查ip
     * @param ip
     * @return
     */
    public static boolean checkIp(String ip) {
        if (ip == null) {
            return false;
        }
        String regex = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$";
        return ip.matches(regex);
    }


    public static String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        String[] arr = ip.split(",");
        ip = arr[0];
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }

    /**
     * 验证密码
     * @param password
     * @return
     */
    public static boolean checkPassword(String password) {
        if (password == null) {
            return false;
        }
//        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$";//数字、字母组合
        String regex = "^[0-9A-Za-z~!@#$%^&*()_+:\"|<>?`=;',./-]{6,18}$";//字母、数字、特殊字符
        return password.matches(regex);
    }

    public static boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }

    //校验是否保留两位小数
    public static boolean isNumber(String str){
        Pattern pattern=Pattern.compile("^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$"); // 判断小数点后2位的数字的正则表达式
        return pattern.matcher(str).matches();
    }

    public static boolean isValidDate(String str) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        try {
            format.setLenient(false);
            format.parse(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 得到一个字符串的长度,显示的长度,一个汉字或日韩文长度为2,英文字符长度为1
     * @param str 需要得到长度的字符串
     * @return int 得到的字符串长度
     */
    public static int length(String str) {
        if (str == null)
            return 0;
        char[] c = str.toCharArray();
        int len = 0;
        for (int i = 0; i < c.length; i++) {
            len++;
            if (!isLetter(c[i])) {
                len++;
            }
        }
        return len;
    }

    public static boolean isLetter(char c) {
        int k = 0x80;
        return c / k == 0 ? true : false;
    }

    public static int getRandom(int min, int max){
        Random random = new Random();
        return random.nextInt(max) % (max - min + 1) + min;
    }
    /**
     * 校验银行卡卡号
     */
    public static boolean isBankCard(String bankCard){
        if(bankCard.length() < 15 || bankCard.length() > 19) {
            return false;
        }
        char bit = getBankCardCheckCode(bankCard.substring(0, bankCard.length() - 1));
        if(bit == 'N'){
            return false;
        }
        return bankCard.charAt(bankCard.length() - 1) == bit;
     }
    /**
     * 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
     * @param nonCheckCodeBankCard
     * @return
     */
     public static   char getBankCardCheckCode(String nonCheckCodeBankCard){
        if(nonCheckCodeBankCard == null || nonCheckCodeBankCard.trim().length() == 0
                || !nonCheckCodeBankCard.matches("\\d+")) {
            //如果传的不是数据返回N
            return 'N';
        }
        char[] chs = nonCheckCodeBankCard.trim().toCharArray();
        int luhmSum = 0;
        for(int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
            int k = chs[i] - '0';
            if(j % 2 == 0) {
                k *= 2;
                k = k / 10 + k % 10;
            }
            luhmSum += k;
        }
        return (luhmSum % 10 == 0) ? '0' : (char)((10 - luhmSum % 10) + '0');
     }

    /****
     * 全国组织机构代码 校验
     * @param organizationCertificate
     * @return
     */
    public static boolean isOrganizationCertificate(String organizationCertificate) {
        String temp = organizationCertificate.toUpperCase();
        if (temp.contains("-")) {
            temp = temp.replace("-", "");
            System.out.println(temp);
        }
        if(temp.length()!=9){
            System.out.println("输入的机构代码位数不对，请核对后再输！");
            return false;
        }
        // 获取前面8位
        String pre8 = temp.substring(0,8);
        char[] pre8chars = pre8.toCharArray();// 0~z;
        // 获取校验码
        String code = temp.substring(8,9);
        boolean isCode = isCode(code,sum(pre8chars));
        System.out.println(isCode?true:"输入的机构代码错误，请核对后再输！");
        return isCode?true:false;
    }

    /**
     * 求和
     * @param bit
     * @return
     */
    private static int sum(char[] bit){
        int power[] = {3,7,9,10,5,8,4,2};
        int sum = 0;
        for(int i=0;i<bit.length;i++){
            int intTemp = bit[i]>'9'?(bit[i]-'A'+10):Integer.parseInt(bit[i]+"");
            System.out.print(" "+intTemp);
            sum +=intTemp*power[i];
        }
        System.out.println();
        System.out.println(sum);
        return  sum;
    }

    /**
     * 判断机构代码的校验码和计算出的校验码是否一致
     * @param a
     * @param b
     * @return
     */
    private static boolean isCode(String a,int b){
        String codeTEmp = (11- b%11)==10?"X":(11- b%11)==11?0+"":(11- b%11)+"";
        System.out.println(codeTEmp);
        return a.equals(codeTEmp);
    }
//是否是微信
    public static boolean isWeChat(String qqorwx) {
        if(StringUtils.isEmpty(qqorwx)){
            return false;
        }//微信号最短是6位最长20位
        Pattern p = Pattern.compile("^[a-zA-Z0-9_-]{5,19}$");
        Matcher m = p.matcher(qqorwx);
        return m.matches();
    }
//是否是Email
    public static boolean isEmail(String email) {
        boolean flag = false;
        try {
            String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
            Pattern regex = Pattern.compile(check);
            Matcher matcher = regex.matcher(email);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
//判断是否是支付宝
    public  static  boolean isAlipay(String aliNum){
        if (checkMobile(aliNum)||isEmail(aliNum))
            return  true;
        return  false;
    }

    //判断身份证是否正确
    /**
     * 二代身份证正则表达式
     *
     * @param idNo
     * @return
     */
    private static boolean isIdNoPattern(String idNo) {
        return Pattern.matches("^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([\\d|x|X]{1})$", idNo);
    }
    //省(直辖市)码表
    private static String provinceCode[] = { "11", "12", "13", "14", "15", "21", "22",
            "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43",
            "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63",
            "64", "65", "71", "81", "82", "91" };
    /**
     * 检查身份证的省份信息是否正确
     * @param provinceId
     * @return
     */
    public static boolean isValidProvinceId(String provinceId){
        for (String id : provinceCode) {
            if (id.equals(provinceId)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 判断日期是否有效
     * @param inDate
     * @return
     */
    public static boolean isValidIDDate(String inDate) {
        if (inDate == null){
            return false;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        if (inDate.trim().length() != dateFormat.toPattern().length()){
            return false;
        }
        dateFormat.setLenient(false);//执行严格的日期匹配
        try {
            dateFormat.parse(inDate.trim());
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
    //身份证前17位每位加权因子
    private static int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    //身份证第18位校检码
    private static String[] refNumber ={"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
    /**
     * 计算身份证的第十八位校验码
     * @param cardIdArray
     * @return
     */
    public static String sumPower(int[] cardIdArray){
        int result = 0;
        for(int i=0;i<power.length;i++){
            result += power[i] * cardIdArray[i];
        }
        return refNumber[(result%11)];
    }
    /**
     * 校验身份证第18位是否正确(只适合18位身份证)
     * @param idNo
     * @return
     */
    public static boolean checkIdNoLastNum(String idNo){
        if(idNo.length() != 18){
            return false;
        }
        char[] tmp = idNo.toCharArray();
        int[] cardidArray = new int[tmp.length-1];
        int i=0;
        for(i=0;i<tmp.length-1;i++){
            cardidArray[i] = Integer.parseInt(tmp[i]+"");
        }
        String checkCode = sumPower(cardidArray);
        String lastNum = tmp[tmp.length-1] + "";
        if(lastNum.equals("x")){
            lastNum = lastNum.toUpperCase();
        }
        if(!checkCode.equals(lastNum)){
            return false;
        }
        return true;
    }

    /**
     * 二代身份证号码有效性校验
     *
     * @param idNo
     * @return
     */
    public static boolean isValidIdNo(String idNo) {
        return isIdNoPattern(idNo) && isValidProvinceId(idNo.substring(0, 2))
                && isValidIDDate(idNo.substring(6, 14)) && checkIdNoLastNum(idNo);
    }



}
